//! 通用测试工具和数据结构
//! 
//! 提供跨测试模块的通用功能，包括：
//! - 测试数据生成器
//! - 测试断言宏
//! - 通用测试配置
//! - 测试工具函数

use std::sync::Arc;
use tokio::sync::RwLock;
use anyhow::Result;

pub mod test_server;

pub mod test_data;

/// 测试配置结构
#[derive(Debug, Clone)]
pub struct TestConfig {
    pub host: String,
    pub port: u16,
    pub timeout_ms: u64,
    pub max_connections: usize,
}

impl Default for TestConfig {
    fn default() -> Self {
        Self {
            host: "127.0.0.1".to_string(),
            port: 6379,
            timeout_ms: 5000,
            max_connections: 100,
        }
    }
}

/// 测试结果结构
#[derive(Debug, PartialEq)]
pub enum TestResult<T> {
    Success(T),
    Failure(String),
    Timeout,
}

impl<T> TestResult<T> {
    pub fn is_success(&self) -> bool {
        matches!(self, TestResult::Success(_))
    }
    
    pub fn is_failure(&self) -> bool {
        matches!(self, TestResult::Failure(_))
    }
    
    pub fn unwrap(self) -> T {
        match self {
            TestResult::Success(value) => value,
            TestResult::Failure(msg) => panic!("TestResult::Failure: {}", msg),
            TestResult::Timeout => panic!("TestResult::Timeout"),
        }
    }
}

/// 异步测试环境设置
pub struct TestEnvironment {
    pub config: TestConfig,
    pub cleanup_tasks: Arc<RwLock<Vec<Box<dyn Fn() + Send + Sync>>>>,
}

impl TestEnvironment {
    pub fn new() -> Self {
        Self {
            config: TestConfig::default(),
            cleanup_tasks: Arc::new(RwLock::new(Vec::new())),
        }
    }
    
    pub fn with_config(config: TestConfig) -> Self {
        Self {
            config,
            cleanup_tasks: Arc::new(RwLock::new(Vec::new())),
        }
    }
    
    /// 添加清理任务
    pub async fn add_cleanup<F>(&self, task: F) 
    where 
        F: Fn() + Send + Sync + 'static 
    {
        let mut cleanup_tasks = self.cleanup_tasks.write().await;
        cleanup_tasks.push(Box::new(task));
    }
    
    /// 执行所有清理任务
    pub async fn cleanup(&self) {
        let cleanup_tasks = self.cleanup_tasks.read().await;
        for task in cleanup_tasks.iter() {
            task();
        }
    }
}

impl Drop for TestEnvironment {
    fn drop(&mut self) {
        // 注意：这里不能使用async，只能进行同步清理
        // 异步清理应该在测试中显式调用cleanup()
    }
}

/// 测试断言宏
#[macro_export]
macro_rules! assert_test_result {
    ($result:expr, $expected:expr) => {
        match $result {
            TestResult::Success(value) => assert_eq!(value, $expected),
            TestResult::Failure(msg) => panic!("测试失败: {}", msg),
            TestResult::Timeout => panic!("测试超时"),
        }
    };
}

#[macro_export]
macro_rules! assert_test_success {
    ($result:expr) => {
        match $result {
            TestResult::Success(_) => {},
            TestResult::Failure(msg) => panic!("期望成功，但失败: {}", msg),
            TestResult::Timeout => panic!("期望成功，但超时"),
        }
    };
}

#[macro_export]
macro_rules! assert_test_failure {
    ($result:expr) => {
        match $result {
            TestResult::Success(_) => panic!("期望失败，但成功"),
            TestResult::Failure(_) => {},
            TestResult::Timeout => panic!("期望失败，但超时"),
        }
    };
}

/// 创建测试用的临时目录
pub fn create_temp_dir() -> Result<tempfile::TempDir> {
    tempfile::tempdir().map_err(|e| anyhow::anyhow!("创建临时目录失败: {}", e))
}

/// 等待条件满足的辅助函数
pub async fn wait_for_condition<F, Fut>(
    mut condition: F,
    timeout_ms: u64,
    check_interval_ms: u64,
) -> bool
where
    F: FnMut() -> Fut,
    Fut: std::future::Future<Output = bool>,
{
    let start = std::time::Instant::now();
    let timeout = std::time::Duration::from_millis(timeout_ms);
    let interval = std::time::Duration::from_millis(check_interval_ms);
    
    while start.elapsed() < timeout {
        if condition().await {
            return true;
        }
        tokio::time::sleep(interval).await;
    }
    
    false
}

/// 生成唯一的测试键名
pub fn generate_test_key(prefix: &str) -> String {
    use std::time::{SystemTime, UNIX_EPOCH};
    let timestamp = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_nanos();
    format!("{}_{}", prefix, timestamp)
}

/// 生成随机测试数据
pub fn generate_random_string(length: usize) -> String {
    use rand::{Rng, distributions::Alphanumeric};
    rand::thread_rng()
        .sample_iter(&Alphanumeric)
        .take(length)
        .map(char::from)
        .collect()
}

/// 生成随机字节数据
pub fn generate_random_bytes(length: usize) -> Vec<u8> {
    use rand::Rng;
    let mut rng = rand::thread_rng();
    (0..length).map(|_| rng.r#gen()).collect()
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_config_default() {
        let config = TestConfig::default();
        assert_eq!(config.host, "127.0.0.1");
        assert_eq!(config.port, 6379);
        assert_eq!(config.timeout_ms, 5000);
        assert_eq!(config.max_connections, 100);
    }
    
    #[test]
    fn test_result_success() {
        let result = TestResult::Success(42);
        assert!(result.is_success());
        assert!(!result.is_failure());
        assert_eq!(result.unwrap(), 42);
    }
    
    #[test]
    fn test_result_failure() {
        let result: TestResult<i32> = TestResult::Failure("test error".to_string());
        assert!(!result.is_success());
        assert!(result.is_failure());
    }
    
    #[test]
    fn test_generate_test_key() {
        let key1 = generate_test_key("test");
        let key2 = generate_test_key("test");
        assert_ne!(key1, key2);
        assert!(key1.starts_with("test_"));
        assert!(key2.starts_with("test_"));
    }
    
    #[test]
    fn test_generate_random_string() {
        let str1 = generate_random_string(10);
        let str2 = generate_random_string(10);
        assert_eq!(str1.len(), 10);
        assert_eq!(str2.len(), 10);
        assert_ne!(str1, str2);
    }
    
    #[test]
    fn test_generate_random_bytes() {
        let bytes1 = generate_random_bytes(20);
        let bytes2 = generate_random_bytes(20);
        assert_eq!(bytes1.len(), 20);
        assert_eq!(bytes2.len(), 20);
        assert_ne!(bytes1, bytes2);
    }
    
    #[tokio::test]
    async fn test_environment_cleanup() {
        let env = TestEnvironment::new();
        let called = Arc::new(RwLock::new(false));
        let called_clone = called.clone();
        
        env.add_cleanup(move || {
            // 这里不能使用async，所以使用同步方式
            // 在实际测试中，清理任务应该是同步的
        }).await;
        
        env.cleanup().await;
        // 验证清理任务被调用（这里简化了验证逻辑）
    }
    
    #[tokio::test]
    async fn test_wait_for_condition() {
        let counter = Arc::new(RwLock::new(0));
        let counter_clone = counter.clone();
        
        // 启动一个任务，在100ms后设置条件为true
        tokio::spawn(async move {
            tokio::time::sleep(std::time::Duration::from_millis(100)).await;
            *counter_clone.write().await = 1;
        });
        
        let result = wait_for_condition(
            || {
                let counter = counter.clone();
                async move {
                    *counter.read().await == 1
                }
            },
            500, // 500ms timeout
            10,  // 每10ms检查一次
        ).await;
        
        assert!(result);
    }
}